#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
图像画布模块，提供图像显示和交互功能。
"""

import sys
import os
import cv2
import numpy as np
from PyQt5.QtCore import Qt, QPoint, pyqtSignal, QRect
from PyQt5.QtGui import QImage, QPixmap, QPainter, QPen, QColor, QCursor, QFont, QBrush
from PyQt5.QtWidgets import QWidget, QSizePolicy

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))

try:
    # 尝试直接导入（从项目根目录运行时）
    from src.core.image_processor import ImageProcessor
except ImportError:
    # 如果失败，尝试使用相对导入（从src目录运行时）
    from core.image_processor import ImageProcessor

# 移除调试输出
# print("ImageCanvas导入的模块:")
# print(f"QSizePolicy已导入: {'QSizePolicy' in globals()}")
# print(f"PyQt5.QtWidgets.QSizePolicy已导入: {'PyQt5.QtWidgets.QSizePolicy' in globals()}")

# 区域调整方向常量
RESIZE_NONE = 0
RESIZE_TOP_LEFT = 1
RESIZE_TOP = 2
RESIZE_TOP_RIGHT = 3
RESIZE_RIGHT = 4
RESIZE_BOTTOM_RIGHT = 5
RESIZE_BOTTOM = 6
RESIZE_BOTTOM_LEFT = 7
RESIZE_LEFT = 8
RESIZE_MOVE = 9

class ImageCanvas(QWidget):
    """图像显示和交互画布"""
    
    # 自定义信号
    region_selected = pyqtSignal(tuple)  # 区域选择信号 (x, y, w, h)
    region_dragged = pyqtSignal(tuple)   # 区域拖动信号 (x, y, w, h)
    point_clicked = pyqtSignal(int, int) # 点击位置信号 (x, y)
    region_right_clicked = pyqtSignal(int, QPoint)  # 右键点击区域信号 (区域索引, 全局位置)
    background_right_clicked = pyqtSignal(int, int, QPoint)  # 右键点击背景信号 (x, y, 全局位置)
    region_adjusted = pyqtSignal(int, tuple)  # 区域调整信号 (区域索引, (x, y, w, h))
    region_double_clicked = pyqtSignal(int)  # 区域双击信号 (区域索引)
    color_picked = pyqtSignal(list)  # 发送RGB颜色值
    
    def __init__(self, parent=None):
        """初始化图像画布
        
        参数:
            parent: 父窗口对象
        """
        super().__init__(parent)
        self.image = None  # 原始图像
        self.displayed_image = None  # 显示用的图像
        self.scale = 1.0  # 缩放比例
        self.scale_y = 1.0  # Y方向缩放比例（兼容性）
        self.offset_x = 0  # X偏移
        self.offset_y = 0  # Y偏移
        self.drag_start_x = None  # 拖拽起始X坐标
        self.drag_start_y = None  # 拖拽起始Y坐标
        self.is_dragging = False  # 是否正在拖拽
        self.drawing = False  # 是否正在绘制
        self.point1 = None  # 绘制矩形的起点
        self.current_rect = None  # 当前绘制的矩形
        self.regions = []  # 已添加区域列表
        self.current_index = -1  # 当前选中区域索引
        self.is_adjusting = False  # 是否正在调整区域
        self.adjust_direction = None  # 调整方向
        self.adjust_start_position = None  # 调整起始位置
        self.adjust_original_rect = None  # 调整前的矩形
        self.resize_handle_size = 10  # 调整柄大小
        self.is_zoomed = False  # 是否处于放大状态
        self.zoomed_region = None  # 放大的区域
        self.suggested_area = None  # 建议选择区域
        self.show_suggestion = True  # 是否显示建议区域
        self.pause_suggestion = False  # 是否暂停建议区域功能
        self.color_picking_mode = False  # 颜色选择模式
        self.base_font_size = 10  # 字体基础大小
        self.sensitivity = 30  # 自动检测敏感度
        
        # 设置聚焦策略
        self.setFocusPolicy(Qt.StrongFocus)
        self.setMouseTracking(True)
        
        # 初始化界面
        self.init_ui()
    
    def init_ui(self):
        """初始化界面设置"""
        # 设置控件属性
        self.setMinimumSize(400, 300)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setMouseTracking(True)  # 跟踪鼠标移动
        self.setFocusPolicy(Qt.StrongFocus)  # 接收键盘事件
        self.setCursor(Qt.CrossCursor)  # 默认十字光标
    
    def set_image(self, image):
        """设置要显示的图像
        
        参数:
            image (numpy.ndarray): 图像数据
        """
        if image is None:
            print("警告: 尝试设置空图像")
            return
            
        # 保存原始图像
        self.image = image
        
        # 获取图像尺寸
        h, w, c = self.image.shape
        bytes_per_line = c * w
        
        # 创建QImage
        q_image = QImage(self.image.data, w, h, bytes_per_line, QImage.Format_RGB888)
        
        # 转换为QPixmap
        pixmap = QPixmap.fromImage(q_image)
        
        # 调整大小以适应控件
        scaled_pixmap = pixmap.scaled(
            self.size(),
            Qt.KeepAspectRatio,
            Qt.SmoothTransformation
        )
        
        # 计算缩放比例
        self.scale = scaled_pixmap.width() / float(w)
        self.scale_y = scaled_pixmap.height() / float(h)
        
        # 保存显示的像素图
        self.displayed_image = scaled_pixmap
        
        # 清除状态
        self.regions = []
        self.current_index = -1
        self.current_rect = None
        self.is_dragging = False
        self.drag_start_x = None
        self.drag_start_y = None
        self.is_adjusting = False
        self.zoomed_region = None
        
        # 强制重绘
        self.update()
    
    def update_display(self):
        """更新图像显示"""
        if self.image is None:
            return
            
        # 检查是否有放大区域
        if self.zoomed_region:
            # 提取放大区域
            x, y, w, h = self.zoomed_region
            display_image = self.image[y:y+h, x:x+w].copy()
            
            # 调整区域绘制坐标
            self.update_adjusted_regions()
        else:
            # 显示整个图像
            display_image = self.image.copy()
            self.adjusted_regions = self.regions.copy() if self.regions else []
            
        # 打印调试信息
        print(f"update_display: adjusted_regions = {self.adjusted_regions}")
            
        # 转换为QImage
        h, w, c = display_image.shape
        bytes_per_line = c * w
        
        # 创建QImage
        q_image = QImage(display_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
        
        # 转换为QPixmap
        pixmap = QPixmap.fromImage(q_image)
        
        # 调整大小以适应控件
        scaled_pixmap = pixmap.scaled(
            self.size(),
            Qt.KeepAspectRatio,
            Qt.SmoothTransformation
        )
        
        # 计算缩放比例
        self.scale_x = scaled_pixmap.width() / float(w)
        self.scale_y = scaled_pixmap.height() / float(h)
        
        # 保存显示的像素图
        self.displayed_image = scaled_pixmap
            
        # 更新窗口
        self.update()
    
    def draw_regions(self, regions=None, current_index=None):
        """绘制区域
        
        参数:
            regions (list): 区域列表，每个区域为 (x, y, w, h, name)
            current_index (int): 当前选中的区域索引
        """
        print(f"调用draw_regions: 传入的regions={regions}, current_index={current_index}")
        
        if regions is not None:
            self.regions = regions
            print(f"已更新regions: self.regions={self.regions}")
            
        if current_index is not None:
            self.current_index = current_index
            
        # 添加调试信息
        print(f"绘制区域: self.regions={self.regions}, self.current_index={self.current_index}")
            
        # 复制原图像进行绘制
        if self.image is not None:
            # 确保adjusted_regions是最新的
            if self.zoomed_region:
                # 放大状态下计算调整后的区域坐标
                self.update_adjusted_regions()
            else:
                # 直接使用self.regions
                self.adjusted_regions = self.regions.copy() if self.regions else []
                
            print(f"adjusted_regions = {self.adjusted_regions}")
            # 触发重绘
            self.update()
    
    def update_adjusted_regions(self):
        """更新调整后的区域坐标（用于放大显示）"""
        if not self.zoomed_region:
            self.adjusted_regions = self.regions.copy() if self.regions else []
            return
            
        # 提取放大区域
        x, y, w, h = self.zoomed_region
        
        # 调整区域绘制坐标
        self.adjusted_regions = []
        for region in self.regions:
            rx, ry, rw, rh = region[:4]
            
            # 计算相对于放大区域的坐标
            adj_x = rx - x
            adj_y = ry - y
            
            # 添加调整后的区域
            if len(region) > 4:
                self.adjusted_regions.append((adj_x, adj_y, rw, rh, region[4]))
            else:
                self.adjusted_regions.append((adj_x, adj_y, rw, rh))
    
    def paintEvent(self, event):
        """绘制事件
        
        参数:
            event: 绘制事件对象
        """
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.SmoothPixmapTransform)
        
        # 填充背景
        painter.fillRect(self.rect(), QColor(50, 50, 50))
        
        # 判断是否有图像加载
        if self.displayed_image is not None:
            # 计算图像在窗口中的位置
            x_offset = (self.width() - self.displayed_image.width()) // 2
            y_offset = (self.height() - self.displayed_image.height()) // 2
            self.image_rect = QRect(x_offset, y_offset, self.displayed_image.width(), self.displayed_image.height())
            
            # 绘制图像
            painter.drawPixmap(self.image_rect, self.displayed_image)
            
            # 调试信息
            print(f"图像绘制位置: x={x_offset}, y={y_offset}, w={self.displayed_image.width()}, h={self.displayed_image.height()}")
            print(f"缩放比例: scale={self.scale}")
            
            # 1. 绘制当前矩形（正在创建的区域）
            if self.current_rect is not None:
                pen = QPen(QColor(0, 255, 0), 2, Qt.DashLine)
                painter.setPen(pen)
                
                x, y, w, h = self.current_rect
                disp_x = int(x * self.scale) + self.image_rect.x()
                disp_y = int(y * self.scale) + self.image_rect.y()
                disp_w = int(w * self.scale)
                disp_h = int(h * self.scale)
                
                painter.drawRect(QRect(disp_x, disp_y, disp_w, disp_h))
            
            # 2. 绘制已添加的区域
            self.manual_draw_regions(painter)
            
            # 3. 绘制建议选择区域
            if self.suggested_area and self.show_suggestion and not self.pause_suggestion:
                self.draw_suggested_region(painter)
        
        painter.end()
    
    def resizeEvent(self, event):
        """Qt尺寸改变事件处理"""
        super().resizeEvent(event)
        
        # 更新图像显示以适应新尺寸
        self.update_display()
    
    def set_sensitivity(self, value):
        """设置像素差敏感度
        
        参数:
            value (int): 敏感度值
        """
        self.sensitivity = value
    
    def mousePressEvent(self, event):
        """鼠标按下事件处理"""
        # 颜色选择模式的处理
        if self.color_picking_mode and event.button() == Qt.LeftButton:
            pos = event.pos()
            color = self.get_color_at(pos.x(), pos.y())
            if color:
                # 如果定义了颜色选择信号，则发送颜色信息
                if hasattr(self, 'color_picked'):
                    self.color_picked.emit(color)
                return  # 不执行其他鼠标处理逻辑
                
        if self.image is None:
            return
        
        # 获取图像坐标
        img_x, img_y = self._get_image_coords(event.pos())
        
        # 检查坐标是否在图像范围内
        if img_x is None or img_y is None:
            return
        
        if event.button() == Qt.LeftButton:
            # 检查是否点击在当前选中区域上
            region_index = self._get_region_at_pos(event.pos())
            
            if region_index >= 0:
                # 点击了区域，检查是否需要调整大小
                direction = self._get_resize_direction(event.pos(), region_index)
                
                if direction != RESIZE_NONE:
                    # 进入调整模式
                    self.is_adjusting = True
                    self.adjust_direction = direction
                    self.adjust_start_position = event.pos()
                    self.current_index = region_index
                    
                    # 保存原始区域数据
                    self.adjust_original_rect = self.regions[region_index][:4]  # 只保存坐标和大小
                    
                    # 更新鼠标指针
                    self._update_cursor(direction)
                    
                    # 刷新显示
                    self.draw_regions()
                    return
            
            # 如果没有点击区域或调整点，开始拖动创建新区域
            self.is_dragging = True
            # 保存图像坐标而非窗口坐标
            self.drag_start_x = img_x
            self.drag_start_y = img_y
        
        elif event.button() == Qt.RightButton:
            # 右键点击
            region_index = self._get_region_at_pos(event.pos())
            
            if region_index >= 0:
                # 点击在区域内，发送右键点击区域信号
                self.region_right_clicked.emit(region_index, event.globalPos())
            else:
                # 点击在背景上，发送右键点击背景信号
                self.background_right_clicked.emit(img_x, img_y, event.globalPos())
    
    def mouseDoubleClickEvent(self, event):
        """鼠标双击事件处理"""
        if self.image is None or event.button() != Qt.LeftButton:
            return
            
        # 获取图像坐标
        img_x, img_y = self._get_image_coords(event.pos())
        
        # 检查坐标是否在图像范围内
        if img_x is None or img_y is None:
            return
            
        # 检查是否双击在区域上
        region_index = self._get_region_at_pos(event.pos())
        
        if region_index >= 0:
            # 切换精细调整模式
            self.is_adjusting = False
            self.current_index = region_index
            
            # 处理放大/恢复操作
            if self.is_adjusting:
                # 放大区域进行精调
                self.zoom_region(region_index)
                
                # 刷新显示
                self.draw_regions()
                
                # 发送双击信号
                self.region_double_clicked.emit(region_index)
                
                # 显示提示
                self.parent().statusBar().showMessage("进入精细调整模式 - 使用方向键微调区域大小，ESC退出")
            else:
                # 如果退出精细调整模式，并且处于放大状态，则恢复
                if self.is_zoomed:
                    self.restore_from_zoom()
                
                # 刷新显示
                self.draw_regions()
                
                self.parent().statusBar().showMessage("已退出精细调整模式")
        # 检查是否有建议区域且双击在建议区域内
        elif self.current_rect and self._is_in_rect(img_x, img_y, self.current_rect):
            # 发出区域选择信号
            self.region_selected.emit(self.current_rect)
            
            # 清除建议区域
            self.clear_suggested_region()
    
    def mouseMoveEvent(self, event):
        """鼠标移动事件处理"""
        if self.image is None:
            return
        
        # 获取图像坐标
        img_x, img_y = self._get_image_coords(event.pos())
        
        # 检查坐标是否在图像范围内
        if img_x is None or img_y is None:
            # 鼠标在图像外，清除建议区域
            if not self.is_dragging and self.current_rect:
                self.clear_suggested_region()
            return
        
        if self.is_dragging:
            # 拖动状态，更新矩形
            orig_x = self.drag_start_x
            orig_y = self.drag_start_y
            
            # 计算矩形
            x = min(orig_x, img_x)
            y = min(orig_y, img_y)
            w = abs(img_x - orig_x)
            h = abs(img_y - orig_y)
            
            self.current_rect = (x, y, w, h)
            
            # 更新显示
            self.update()
        elif self.is_adjusting and self.current_index >= 0:
            # 调整状态，根据方向调整区域大小
            self._adjust_region(event.pos())
        else:
            # 保存当前的建议区域，用于检查鼠标是否移出
            old_rect = self.current_rect
            
            # 非拖动和调整状态，更新鼠标指针
            region_index = self._get_region_at_pos(event.pos())
            
            if region_index >= 0:
                # 鼠标在区域上，根据位置更新指针
                direction = self._get_resize_direction(event.pos(), region_index)
                self._update_cursor(direction)
            else:
                # 鼠标不在区域上，恢复默认指针
                self.setCursor(Qt.ArrowCursor)
                
                try:
                    # 尝试检测建议区域
                    processor = ImageProcessor()
                    suggested_rect = processor.detect_area(self.image, img_x, img_y, self.sensitivity)
                    
                    # 判断鼠标是否在之前检测到的区域内
                    if old_rect and not self._is_in_rect(img_x, img_y, old_rect):
                        # 鼠标已经移出之前的建议区域，清除它
                        self.clear_suggested_region()
                    
                    # 检查是否有新的区域建议
                    if suggested_rect:
                        if suggested_rect != old_rect:  # 只有当建议区域改变时才更新显示
                            # 保存建议的剪切区域
                            self.current_rect = suggested_rect
                            
                            # 更新显示
                            self.draw_suggested_region(suggested_rect)
                except Exception as e:
                    print(f"自动检测区域预览出错: {str(e)}")
    
    def mouseReleaseEvent(self, event):
        """鼠标释放事件
        
        参数:
            event: 鼠标事件对象
        """
        # 如果不是左键，则忽略
        if event.button() != Qt.LeftButton:
            return
            
        # 检查是否在拖动
        if self.is_dragging:
            # 获取图像坐标
            img_x = (event.pos().x() - self.image_rect.x()) / self.scale
            img_y = (event.pos().y() - self.image_rect.y()) / self.scale
            
            # 计算矩形
            w = abs(img_x - self.drag_start_x)
            h = abs(img_y - self.drag_start_y)
            x = min(img_x, self.drag_start_x)
            y = min(img_y, self.drag_start_y)
            
            # 如果矩形太小，则忽略
            if w < 5 or h < 5:
                print("矩形太小，忽略")
                self.is_dragging = False
                self.current_rect = None
                self.update()
                return
                
            # 创建矩形区域 - 转换为整数值
            self.current_rect = (int(x), int(y), int(w), int(h))
            
            # 触发区域选择信号
            self.region_selected.emit(self.current_rect)
            
            # 重置状态
            self.is_dragging = False
            
        # 强制重绘
        self.update()
    
    def keyPressEvent(self, event):
        """键盘按下事件处理"""
        # 检查是否在精细调整模式
        if not self.is_adjusting or self.current_index < 0:
            # 不在精细调整模式，传递给基类
            super().keyPressEvent(event)
            return
            
        # 获取当前区域数据
        region = list(self.regions[self.current_index])
        changed = False
        
        # 使用方向键微调
        if event.key() == Qt.Key_Left:
            # 左箭头 - 水平缩小或左移
            if event.modifiers() & Qt.ShiftModifier:
                # 按住Shift - 左侧调整（缩小宽度）
                region[2] = max(10, region[2] - 1)
            elif event.modifiers() & Qt.ControlModifier:
                # 按住Ctrl - 右侧调整（缩小宽度）
                region[0] += 1
                region[2] = max(10, region[2] - 1)
            else:
                # 左移
                region[0] -= 1
            changed = True
            
        elif event.key() == Qt.Key_Right:
            # 右箭头 - 水平扩大或右移
            if event.modifiers() & Qt.ShiftModifier:
                # 按住Shift - 右侧调整（增加宽度）
                region[2] += 1
            elif event.modifiers() & Qt.ControlModifier:
                # 按住Ctrl - 左侧调整（增加宽度）
                region[0] -= 1
                region[2] += 1
            else:
                # 右移
                region[0] += 1
            changed = True
            
        elif event.key() == Qt.Key_Up:
            # 上箭头 - 垂直缩小或上移
            if event.modifiers() & Qt.ShiftModifier:
                # 按住Shift - 上侧调整（缩小高度）
                region[3] = max(10, region[3] - 1)
            elif event.modifiers() & Qt.ControlModifier:
                # 按住Ctrl - 下侧调整（缩小高度）
                region[1] += 1
                region[3] = max(10, region[3] - 1)
            else:
                # 上移
                region[1] -= 1
            changed = True
            
        elif event.key() == Qt.Key_Down:
            # 下箭头 - 垂直扩大或下移
            if event.modifiers() & Qt.ShiftModifier:
                # 按住Shift - 下侧调整（增加高度）
                region[3] += 1
            elif event.modifiers() & Qt.ControlModifier:
                # 按住Ctrl - 上侧调整（增加高度）
                region[1] -= 1
                region[3] += 1
            else:
                # 下移
                region[1] += 1
            changed = True
            
        elif event.key() == Qt.Key_Escape:
            # ESC键 - 退出精细调整模式
            self.is_adjusting = False
            
            # 如果处于放大状态，恢复原始视图
            if self.is_zoomed:
                self.restore_from_zoom()
            else:
                # 否则只更新绘制
                self.draw_regions()
            
            # 显示提示
            self.parent().statusBar().showMessage("已退出精细调整模式")
            return
        
        # 如果区域发生变化，更新并重绘
        if changed:
            # 检查区域是否超出图像边界
            if self.image is not None:
                h, w = self.image.shape[:2]
                region[0] = max(0, min(region[0], w - region[2]))
                region[1] = max(0, min(region[1], h - region[3]))
            
            # 更新区域
            self.regions[self.current_index] = tuple(region)
            
            # 重绘
            self.draw_regions()
            
            # 发送区域调整信号
            self.region_adjusted.emit(self.current_index, (region[0], region[1], region[2], region[3]))
        else:
            # 没有处理的键，传递给基类
            super().keyPressEvent(event)
    
    def _adjust_region(self, pos):
        """根据鼠标位置调整区域
        
        参数:
            pos (QPoint): 当前鼠标位置
        """
        if self.adjust_start_position is None or self.adjust_direction == RESIZE_NONE:
            return
            
        # 计算鼠标移动距离（窗口坐标）
        dx = pos.x() - self.adjust_start_position.x()
        dy = pos.y() - self.adjust_start_position.y()
        
        # 转换为图像坐标
        dx_img = int(dx / self.scale_x)
        dy_img = int(dy / self.scale_y)
        
        # 获取原始区域数据
        orig_x, orig_y, orig_w, orig_h = self.adjust_original_rect
        
        # 新的区域数据
        new_x, new_y, new_w, new_h = orig_x, orig_y, orig_w, orig_h
        
        # 根据调整方向更新区域
        if self.adjust_direction in (RESIZE_LEFT, RESIZE_TOP_LEFT, RESIZE_BOTTOM_LEFT):
            # 左边调整
            new_x = orig_x + dx_img
            new_w = orig_w - dx_img
        
        if self.adjust_direction in (RESIZE_RIGHT, RESIZE_TOP_RIGHT, RESIZE_BOTTOM_RIGHT):
            # 右边调整
            new_w = orig_w + dx_img
        
        if self.adjust_direction in (RESIZE_TOP, RESIZE_TOP_LEFT, RESIZE_TOP_RIGHT):
            # 上边调整
            new_y = orig_y + dy_img
            new_h = orig_h - dy_img
        
        if self.adjust_direction in (RESIZE_BOTTOM, RESIZE_BOTTOM_LEFT, RESIZE_BOTTOM_RIGHT):
            # 下边调整
            new_h = orig_h + dy_img
        
        if self.adjust_direction == RESIZE_MOVE:
            # 整体移动
            new_x = orig_x + dx_img
            new_y = orig_y + dy_img
        
        # 确保宽高不小于最小值
        if new_w < 10:
            if self.adjust_direction in (RESIZE_LEFT, RESIZE_TOP_LEFT, RESIZE_BOTTOM_LEFT):
                new_x = orig_x + orig_w - 10
            new_w = 10
        
        if new_h < 10:
            if self.adjust_direction in (RESIZE_TOP, RESIZE_TOP_LEFT, RESIZE_TOP_RIGHT):
                new_y = orig_y + orig_h - 10
            new_h = 10
        
        # 确保不超出图像边界
        if self.image is not None:
            h, w = self.image.shape[:2]
            
            if new_x < 0:
                if self.adjust_direction == RESIZE_MOVE:
                    # 移动时限制在边界内
                    new_x = 0
                else:
                    # 调整大小时，修正宽度
                    new_w += new_x
                    new_x = 0
            
            if new_y < 0:
                if self.adjust_direction == RESIZE_MOVE:
                    new_y = 0
                else:
                    new_h += new_y
                    new_y = 0
            
            if new_x + new_w > w:
                if self.adjust_direction == RESIZE_MOVE:
                    new_x = w - new_w
                else:
                    new_w = w - new_x
            
            if new_y + new_h > h:
                if self.adjust_direction == RESIZE_MOVE:
                    new_y = h - new_h
                else:
                    new_h = h - new_y
        
        # 更新区域
        region = list(self.regions[self.current_index])
        region[0] = new_x
        region[1] = new_y
        region[2] = new_w
        region[3] = new_h
        self.regions[self.current_index] = tuple(region)
        
        # 使用完全重绘方式更新显示，避免拖影
        self.draw_regions()
    
    def _update_cursor(self, direction):
        """根据调整方向更新鼠标指针
        
        参数:
            direction (int): 调整方向常量
        """
        if direction == RESIZE_TOP_LEFT or direction == RESIZE_BOTTOM_RIGHT:
            self.setCursor(Qt.SizeFDiagCursor)
        elif direction == RESIZE_TOP_RIGHT or direction == RESIZE_BOTTOM_LEFT:
            self.setCursor(Qt.SizeBDiagCursor)
        elif direction == RESIZE_LEFT or direction == RESIZE_RIGHT:
            self.setCursor(Qt.SizeHorCursor)
        elif direction == RESIZE_TOP or direction == RESIZE_BOTTOM:
            self.setCursor(Qt.SizeVerCursor)
        elif direction == RESIZE_MOVE:
            self.setCursor(Qt.SizeAllCursor)
        else:
            self.setCursor(Qt.ArrowCursor)
    
    def _get_image_coords(self, pos):
        """将窗口坐标转换为图像坐标
        
        参数:
            pos (QPoint): 窗口坐标
            
        返回:
            tuple: (图像x坐标, 图像y坐标) 或 (None, None)
        """
        if self.image is None or self.displayed_image is None:
            return None, None
        
        # 计算图像在窗口中的位置
        x_offset = (self.width() - self.displayed_image.width()) // 2
        y_offset = (self.height() - self.displayed_image.height()) // 2
        
        # 窗口坐标相对于图像的偏移
        rel_x = pos.x() - x_offset
        rel_y = pos.y() - y_offset
        
        # 检查是否在图像范围内
        if (0 <= rel_x < self.displayed_image.width() and
            0 <= rel_y < self.displayed_image.height()):
            # 转换为图像坐标
            img_x = int(rel_x / self.scale)
            img_y = int(rel_y / self.scale)
            
            # 检查边界
            img_x = max(0, min(img_x, self.image.shape[1] - 1))
            img_y = max(0, min(img_y, self.image.shape[0] - 1))
            
            return img_x, img_y
        else:
            return None, None
    
    def _get_region_at_pos(self, pos):
        """获取指定位置对应的区域索引
        
        参数:
            pos (QPoint): 窗口坐标
            
        返回:
            int: 区域索引，如果没有区域则返回-1
        """
        if not self.regions:
            return -1
            
        # 获取图像坐标
        img_x, img_y = self._get_image_coords(pos)
        
        if img_x is None or img_y is None:
            return -1
            
        # 遍历区域检查位置
        for i, region in enumerate(self.regions):
            # 确保区域数据有效
            if len(region) >= 4:
                x, y, w, h = region[:4]  # 只解包前4个值
                
                # 检查点是否在区域内
                if x <= img_x <= x + w and y <= img_y <= y + h:
                    return i
                    
        return -1
    
    def draw_suggested_region(self, painter):
        """绘制建议选择区域
        
        参数:
            painter (QPainter): 绘图对象
        """
        if not self.suggested_area:
            return
            
        x, y, w, h = self.suggested_area
        
        # 转换为显示坐标
        disp_x = int(x * self.scale) + self.image_rect.x()
        disp_y = int(y * self.scale) + self.image_rect.y()
        disp_w = int(w * self.scale)
        disp_h = int(h * self.scale)
        
        # 绘制矩形
        pen = QPen(QColor(255, 165, 0), 2, Qt.DashLine)
        painter.setPen(pen)
        painter.drawRect(QRect(disp_x, disp_y, disp_w, disp_h))
        
        # 绘制提示文字
        font = painter.font()
        font.setBold(True)
        font.setPointSize(12)
        painter.setFont(font)
        painter.setPen(QColor(255, 165, 0))
        painter.drawText(QRect(disp_x, disp_y - 20, 100, 20), Qt.AlignLeft, "建议区域")
    
    def clear_suggested_region(self):
        """清除建议选择区域"""
        self.suggested_area = None
        self.update()
    
    def _is_in_rect(self, x, y, rect):
        """检查坐标是否在矩形内
        
        参数:
            x (int): X坐标
            y (int): Y坐标
            rect (tuple): 矩形 (x, y, w, h)
            
        返回:
            bool: 在矩形内返回True，否则False
        """
        rx, ry, rw, rh = rect
        return rx <= x < rx + rw and ry <= y < ry + rh
    
    def _get_resize_direction(self, pos, region_index):
        """获取调整方向
        
        参数:
            pos (QPoint): 鼠标位置
            region_index (int): 区域索引
            
        返回:
            int: 调整方向
        """
        if self.regions is None or region_index < 0 or region_index >= len(self.regions):
            return RESIZE_NONE
            
        # 获取区域数据，确保有效
        region = self.regions[region_index]
        if len(region) < 4:
            return RESIZE_NONE
            
        # 解析区域坐标
        x, y, w, h = region[:4]
        
        # 计算显示坐标
        image_x = self.image_rect.x() if hasattr(self, 'image_rect') else 0
        image_y = self.image_rect.y() if hasattr(self, 'image_rect') else 0
        
        disp_x = int(x * self.scale) + image_x
        disp_y = int(y * self.scale) + image_y
        disp_w = int(w * self.scale)
        disp_h = int(h * self.scale)
        
        # 设置检测区域大小
        handle_size = self.resize_handle_size
        half_size = handle_size // 2
        
        # 获取鼠标位置
        mx, my = pos.x(), pos.y()
        
        # 右下角
        if abs(mx - (disp_x + disp_w)) <= half_size and abs(my - (disp_y + disp_h)) <= half_size:
            return RESIZE_BOTTOM_RIGHT
        # 右上角
        elif abs(mx - (disp_x + disp_w)) <= half_size and abs(my - disp_y) <= half_size:
            return RESIZE_TOP_RIGHT
        # 左下角
        elif abs(mx - disp_x) <= half_size and abs(my - (disp_y + disp_h)) <= half_size:
            return RESIZE_BOTTOM_LEFT
        # 左上角
        elif abs(mx - disp_x) <= half_size and abs(my - disp_y) <= half_size:
            return RESIZE_TOP_LEFT
        # 上边中点
        elif abs(mx - (disp_x + disp_w/2)) <= half_size and abs(my - disp_y) <= half_size:
            return RESIZE_TOP
        # 右边中点
        elif abs(mx - (disp_x + disp_w)) <= half_size and abs(my - (disp_y + disp_h/2)) <= half_size:
            return RESIZE_RIGHT
        # 下边中点
        elif abs(mx - (disp_x + disp_w/2)) <= half_size and abs(my - (disp_y + disp_h)) <= half_size:
            return RESIZE_BOTTOM
        # 左边中点
        elif abs(mx - disp_x) <= half_size and abs(my - (disp_y + disp_h/2)) <= half_size:
            return RESIZE_LEFT
        else:
            return RESIZE_NONE
    
    def zoom_region(self, region_index):
        """放大指定区域以便精调
        
        参数:
            region_index (int): 要放大的区域索引
        """
        if region_index < 0 or region_index >= len(self.regions) or self.image is None:
            return False
            
        # 已经是放大状态，不再执行
        if self.is_zoomed:
            return True
            
        # 备份原始图像和当前状态
        self.original_image_copy = self.image.copy()
        
        # 获取区域数据
        x, y, w, h, _ = self.regions[region_index]
        
        # 扩展区域以提供一些边距（每边增加10%）
        margin_x = max(10, int(w * 0.1))
        margin_y = max(10, int(h * 0.1))
        
        # 获取图像尺寸
        img_h, img_w = self.image.shape[:2]
        
        # 计算扩展后的区域，确保不超出图像边界
        crop_x = max(0, x - margin_x)
        crop_y = max(0, y - margin_y)
        crop_w = min(img_w - crop_x, w + 2 * margin_x)
        crop_h = min(img_h - crop_y, h + 2 * margin_y)
        
        # 保存放大区域的原始坐标
        self.zoomed_region = (crop_x, crop_y, crop_w, crop_h)
        
        # 裁剪区域
        cropped = self.image[crop_y:crop_y+crop_h, crop_x:crop_x+crop_w].copy()
        
        # 调整区域坐标（相对于裁剪区域）
        for i, (rx, ry, rw, rh, rn) in enumerate(self.regions):
            new_x = rx - crop_x
            new_y = ry - crop_y
            self.regions[i] = (new_x, new_y, rw, rh, rn)
        
        # 设置新的图像
        self.image = cropped
        self.is_zoomed = True
        
        # 更新显示
        self.update_display()
        
        return True
    
    def restore_from_zoom(self):
        """从放大状态恢复"""
        if not self.is_zoomed or self.original_image_copy is None:
            return False
            
        # 获取之前放大的区域
        crop_x, crop_y, crop_w, crop_h = self.zoomed_region
        
        # 调整区域坐标（恢复到原始图像坐标）
        for i, (rx, ry, rw, rh, rn) in enumerate(self.regions):
            new_x = rx + crop_x
            new_y = ry + crop_y
            self.regions[i] = (new_x, new_y, rw, rh, rn)
        
        # 恢复原始图像
        self.image = self.original_image_copy
        self.original_image_copy = None
        self.zoomed_region = None
        self.is_zoomed = False
        
        # 更新显示
        self.update_display()
        
        return True
    
    def enable_color_picking(self, enabled):
        """启用/禁用颜色选择模式
        
        参数:
            enabled (bool): 是否启用颜色选择
        """
        self.color_picking_mode = enabled
        
        # 更新鼠标样式
        if enabled:
            self.setCursor(Qt.CrossCursor)
        else:
            self.setCursor(Qt.ArrowCursor)
    
    def get_color_at(self, x, y):
        """获取指定位置的颜色
        
        参数:
            x (int): X坐标
            y (int): Y坐标
            
        返回:
            list: RGB颜色值 [r, g, b] 或 None
        """
        try:
            # 将屏幕坐标转换为图像坐标
            if hasattr(self, 'image_rect') and self.image_rect.contains(x, y):
                # 调整为图像相对坐标
                img_x = int((x - self.image_rect.x()) / self.scale_x)
                img_y = int((y - self.image_rect.y()) / self.scale_y)
                
                # 确保在图像范围内
                if isinstance(self.image, np.ndarray):
                    h, w = self.image.shape[:2]
                    if 0 <= img_x < w and 0 <= img_y < h:
                        # 获取BGR颜色值
                        color = self.image[img_y, img_x]
                        # 转换为RGB
                        return [int(color[2]), int(color[1]), int(color[0])]
                else:
                    # QImage
                    qimg = self.image
                    if 0 <= img_x < qimg.width() and 0 <= img_y < qimg.height():
                        pixel = qimg.pixel(img_x, img_y)
                        qcolor = QColor(pixel)
                        return [qcolor.red(), qcolor.green(), qcolor.blue()]
        except Exception as e:
            print(f"获取颜色时出错: {e}")
            
        return None
    
    def zoom_to_region(self, region_index):
        """放大显示指定区域
        
        参数:
            region_index (int): 区域索引
        """
        # 检查索引有效性和图像是否已加载
        if self.image is None or region_index < 0 or region_index >= len(self.regions):
            return False
            
        # 获取区域数据
        region = self.regions[region_index]
        x, y, w, h = region[:4]
        
        # 确保区域有效
        if w <= 0 or h <= 0:
            return False
            
        # 计算放大区域（添加边距）
        margin = 20  # 像素边距
        zoom_x = max(0, x - margin)
        zoom_y = max(0, y - margin)
        zoom_w = min(w + 2 * margin, self.image.shape[1] - zoom_x)
        zoom_h = min(h + 2 * margin, self.image.shape[0] - zoom_y)
        
        # 保存放大区域信息
        self.zoomed_region = (zoom_x, zoom_y, zoom_w, zoom_h)
        
        # 更新显示
        self.update_display()
        
        return True
    
    def reset_zoom(self):
        """重置缩放状态"""
        if self.zoomed_region:
            self.zoomed_region = None
            self.update_display()
    
    def clear_regions(self):
        """清除所有区域"""
        self.regions = []
        self.current_index = -1
        self.zoomed_region = None
        self.current_rect = None
        self.is_adjusting = False
        self.is_dragging = False
        self.drag_start_x = None
        self.drag_start_y = None
        self.resize_direction = None
        self.suggested_area = None
        self.show_suggestion = True
        self.pause_suggestion = False
        self.color_picking_mode = False
        
        # 更新显示
        self.update()
    
    def suggest_area(self, rect=None):
        """建议剪切区域
        
        参数:
            rect: 手动指定的区域，如果为None则自动计算
        """
        if self.image is None or self.pause_suggestion:
            return
            
        if rect:
            self.suggested_area = rect
        else:
            # 使用OpenCV自动检测区域
            try:
                img_np = self.convert_qimage_to_numpy(self.image)
                gray = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)
                blurred = cv2.GaussianBlur(gray, (5, 5), 0)
                edged = cv2.Canny(blurred, 50, 100)
                
                # 查找轮廓
                contours, _ = cv2.findContours(edged, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
                
                # 选择最大的轮廓
                if contours:
                    max_contour = max(contours, key=cv2.contourArea)
                    x, y, w, h = cv2.boundingRect(max_contour)
                    
                    # 确保区域合理
                    if w > 20 and h > 20:
                        # 如果区域接近图像边缘，则认为是整个图像
                        if (x < 10 and y < 10 and 
                            x + w > self.image.width() - 10 and 
                            y + h > self.image.height() - 10):
                            # 建议更小的区域
                            margin = min(self.image.width(), self.image.height()) // 10
                            x = margin
                            y = margin
                            w = self.image.width() - 2 * margin
                            h = self.image.height() - 2 * margin
                        
                        self.suggested_area = (x, y, w, h)
            except Exception as e:
                print(f"自动建议区域时出错: {e}")
                
        # 更新显示
        self.update() 
    
    def update_region(self, region_index, rect):
        """更新指定区域的坐标和大小
        
        参数:
            region_index (int): 区域索引
            rect (tuple): 区域坐标和大小 (x, y, w, h) 或 (x, y, w, h, name)
        """
        if region_index < 0 or region_index >= len(self.regions):
            return
            
        # 获取区域名称
        name = None
        if len(self.regions[region_index]) > 4:
            name = self.regions[region_index][4]
        
        # 检查rect是否包含名称
        if len(rect) > 4:
            # 使用传入的名称
            name = rect[4]
            
        # 更新区域
        if name:
            self.regions[region_index] = (rect[0], rect[1], rect[2], rect[3], name)
        else:
            self.regions[region_index] = rect
            
        # 如果当前放大显示该区域，则更新显示
        if self.zoomed_region is not None and self.current_index == region_index:
            self.zoom_to_region(region_index)
            
        # 更新显示
        self.update()
    
    def draw_manual_rect(self, x, y, w, h, color, thickness=2, style=Qt.SolidLine):
        """手动绘制指定区域的矩形框
        
        参数:
            x, y, w, h: 区域坐标和尺寸
            color: 颜色对象
            thickness: 线条粗细
            style: 线条样式
        """
        # 检查图像是否已加载
        if self.image is None or self.displayed_image is None:
            return
            
        # 创建QPainter
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        # 设置画笔
        pen = QPen(color, thickness, style)
        painter.setPen(pen)
        painter.setBrush(Qt.NoBrush)
        
        # 计算显示坐标
        disp_x = int(x * self.scale_x) + self.image_rect.x()
        disp_y = int(y * self.scale_y) + self.image_rect.y()
        disp_w = int(w * self.scale_x)
        disp_h = int(h * self.scale_y)
        
        # 绘制矩形
        painter.drawRect(disp_x, disp_y, disp_w, disp_h)
        
        # 结束绘制
        painter.end()
        
        # 调试信息
        print(f"手动绘制矩形: 原始=({x},{y},{w},{h}), 显示=({disp_x},{disp_y},{disp_w},{disp_h})")
        
    def manual_draw_regions(self, painter=None):
        """手动绘制区域，用于处理问题
        
        参数:
            painter: QPainter对象，如果为None则使用update()更新画布
        """
        # 检查区域和图像
        if not self.regions or self.image is None:
            print("没有区域可绘制或图像未加载")
            if painter is None:
                self.update()  # 没有传入painter，使用update强制更新画布
            return
            
        # 如果没有传入painter，则使用update()强制更新画布
        if painter is None:
            self.update()
            return
            
        # 遍历区域
        print(f"正在绘制 {len(self.regions)} 个区域")
        for i, region in enumerate(self.regions):
            if region:
                # 确保只获取前4个值(x,y,w,h)，忽略可能存在的其他值
                if len(region) >= 4:
                    x, y, w, h = region[:4]  # 只解包前4个值
                else:
                    print(f"区域 {i} 数据不完整，跳过绘制")
                    continue
                
                # 将相对坐标转换为显示坐标
                image_x = self.image_rect.x() if hasattr(self, 'image_rect') else 0
                image_y = self.image_rect.y() if hasattr(self, 'image_rect') else 0
                
                disp_x = int(x * self.scale) + image_x
                disp_y = int(y * self.scale) + image_y
                disp_w = int(w * self.scale)
                disp_h = int(h * self.scale)
                
                # 选择颜色，当前选中区域使用不同颜色
                color = QColor(255, 0, 0) if i == self.current_index else QColor(0, 0, 255)
                
                # 设置画笔
                pen = QPen(color, 2, Qt.SolidLine)
                painter.setPen(pen)
                
                # 绘制矩形
                painter.drawRect(QRect(disp_x, disp_y, disp_w, disp_h))
                print(f"手动绘制区域 {i}: 原始=({x},{y},{w},{h}), 显示=({disp_x},{disp_y},{disp_w},{disp_h})")
                
                # 显示区域索引
                font = painter.font()
                font.setBold(True)
                font.setPointSize(12)
                painter.setFont(font)
                painter.setPen(QColor(255, 255, 0))
                painter.drawText(QRect(disp_x, disp_y, disp_w, 20), Qt.AlignCenter, str(i+1)) 